﻿//////////////////////////////////////////////////////////////////////////////
//
//  Copyright © 1998-2024 Glodon Company Limited.  All rights reserved.
//
//  Use of this software is subject to the terms of the Glodon license
//  agreement provided at the time of installation or download, or which
//  otherwise accompanies this software in either electronic or hard copy form.  
//
//////////////////////////////////////////////////////////////////////////////

// Reviewed

#pragma once

#include "Box3d.h"
#include "Coordinate3d.h"
#include "Vector3d.h"
#include "MathUtils.h"

namespace gcmp
{

    /// \brief 三维紧包围盒的定义
    ///
    /// 
    class GCMP_MATH_INTERFACE_EXPORT TiltBox3d
    {
    public:
        DEFINE_VISUAL_TYPE_DOUBLE()

    public:

        /// \brief  创建一个空的紧包围盒
        ///
        /// \return  空的紧包围盒
        static TiltBox3d CreateEmptyTiltBox3d();

        /// \brief   创建一个紧包围盒
        ///
        /// \param coord 坐标系
        /// \param box 包围盒
        /// \return  紧包围盒
        static TiltBox3d Create(const Coordinate3d &coord, const Box3d &box);

        /// \brief  设置坐标系
        ///
        /// \param coord 坐标系
        /// \return true:成功， false:失败
        bool SetCoordinate(const Coordinate3d &coord);
        
        /// \brief  获取坐标系
        ///
        /// \return 坐标系
        const Coordinate3d& GetCoordinate() const;

        /// \brief  设置包围盒
        ///
        /// \param box  包围盒
        /// \return  true:成功， false:失败
        bool SetBox(const Box3d &box);

        /// \brief  获取包围盒
        ///
        /// \return  包围盒
        const Box3d& GetBox() const;

        /// \brief  求包围盒
        ///
        /// \return 包围盒
        Box3d BoundingBox() const;

        /// \brief  判断是否为空
        ///
        /// \return true:是， false:否
        bool IsEmpty() const;

        /// \brief   在给定误差内，判断两包围盒是否相交
        ///
        /// \param box   另一个紧包围盒
        /// \param epsilon  给定误差
        /// \return  true: 包含， false: 不包含
        bool IsIntersect(const TiltBox3d & box, double epsilon = gcmp::Constants::DOUBLE_EPS) const;

        /// \brief   在给定误差内，判断当前包围盒是否包含传入点（不在包围盒上）
        ///
        /// \param rPt  传入点
        /// \param epsilon  给定误差
        /// \return  true: 在内部， false: 不在内部
        bool IsPointInBox(const Vector3d & rPt, double epsilon = gcmp::Constants::DOUBLE_EPS) const;

        /// \brief   在给定误差内，判断当前点是否在包围盒上
        ///
        /// \param rPt  传入点
        /// \param epsilon  给定误差
        /// \return   true: 在包围盒上， false: 不在包围盒上
        bool IsPointOnBox(const Vector3d & rPt, double epsilon = Constants::DOUBLE_EPS) const;

    public:
        /// \brief  默认构造函数
        /// 
        TiltBox3d();

        /// \brief 构造函数
        ///
        /// \param coord 坐标系
        /// \param box 包围盒
        ///
        TiltBox3d(const Coordinate3d &coord, const Box3d &box);


        /// \brief  获取坐标系原点
        ///
        /// \return 坐标系原点
        const Vector3d& Origin() const;

        /// \brief  获取紧包围盒的中心
        ///
        /// \return 紧包围盒的中心
        Vector3d Center() const;

    private:
        /// \brief 获取紧包围盒的基向量
        ///
        /// \param vx  基向量x
        /// \param vy  基向量y
        /// \param vz  基向量z
        ///  
        void GetHalfBaseVectors(Vector3d & vx, Vector3d & vy, Vector3d & vz) const;

        /// \brief TiltBox的位置关系
        enum class TiltBoxPosition : int32_t
        {
            TBP_Intersection = 0, ///< 相交
            TBP_Tangent = 1,      ///< 相切            
            TBP_Disjoin = 2       ///< 分离
        };

        /// \brief 判断TiltBox的位置关系
        ///
        /// \param other  另外一个紧包围盒
        /// \param distEpsilon  容差
        TiltBoxPosition CheckPosition(const TiltBox3d& other, double distEpsilon = Constants::DOUBLE_EPS) const;

    private:
        Coordinate3d m_coord;    //局部坐标系
        Box3d   m_box;           //局部坐标系的Box
    };
}

